﻿using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using X.Infrastructure.Shapes;
using X.WPF.Controls.Enums;
using X.WPF.Controls.EventArgs.CanvasShapeArgs;
using X.WPF.Controls.EventArgs.DraggableControlArgs;

namespace X.WPF.Controls.CustomControls
{
    /// <summary>
    /// 画布型状
    /// </summary>
    public abstract class CanvasShape : ContentControl
    {
        #region # 字段及构造器

        /// <summary>
        /// 父节点画布
        /// </summary>
        protected Canvas _parentCanvas => this.Parent as Canvas;

        /// <summary>
        /// 静态构造器
        /// </summary>
        static CanvasShape()
        {
            //注册依赖属性
            CanvasShape.TextProperty = DependencyProperty.Register(nameof(CanvasShape.Text), typeof(string), typeof(CanvasShape), new PropertyMetadata(string.Empty));
            CanvasShape.StrokeProperty = DependencyProperty.Register(nameof(CanvasShape.Stroke), typeof(Brush), typeof(CanvasShape), new PropertyMetadata(Brushes.Transparent));
            CanvasShape.StrokeThicknessProperty = DependencyProperty.Register(nameof(CanvasShape.StrokeThickness), typeof(double), typeof(CanvasShape), new PropertyMetadata(1d));
            CanvasShape.FillProperty = DependencyProperty.Register(nameof(CanvasShape.Fill), typeof(Brush), typeof(CanvasShape), new PropertyMetadata(Brushes.Transparent));
            CanvasShape.ZIndexProperty = DependencyProperty.Register(nameof(CanvasShape.ZIndex), typeof(int), typeof(CanvasShape), new PropertyMetadata(0));

            //注册路由事件
            CanvasShape._ShapeClickEvent = EventManager.RegisterRoutedEvent(nameof(CanvasShape.ShapeClick), RoutingStrategy.Direct, typeof(CanvasShapeClickEventHandler), typeof(CanvasShape));
            CanvasShape._ShapeDrawnEvent = EventManager.RegisterRoutedEvent(nameof(CanvasShape.ShapeDrawn), RoutingStrategy.Direct, typeof(CanvasShapeDrawnEventHandler), typeof(CanvasShape));
            CanvasShape._ShapeDrawCancelEvent = EventManager.RegisterRoutedEvent(nameof(CanvasShape.ShapeDrawCancel), RoutingStrategy.Direct, typeof(CanvasShapeDrawCancelEventHandler), typeof(CanvasShape));
        }

        /// <summary>
        /// 默认构造器
        /// </summary>
        protected CanvasShape(CanvasShapeType shapeType)
        {
            this.Visibility = Visibility.Collapsed;
            this.ShapeType = shapeType;

            this.InitElement();
        }

        #endregion

        #region # 属性

        #region 形状类型 —— CanvasShapeType ShapeType
        /// <summary>
        /// 形状类型
        /// </summary>
        public CanvasShapeType ShapeType { get; protected set; }
        #endregion

        #region 形状控件 —— Shape ShapeElement
        /// <summary>
        /// 形状控件
        /// </summary>
        public Shape ShapeElement { get; protected set; }
        #endregion

        #endregion

        #region # 依赖属性

        #region 文本 —— string Text
        /// <summary>
        /// 文本依赖属性
        /// </summary>
        public static DependencyProperty TextProperty;

        /// <summary>
        /// 文本
        /// </summary>
        public string Text
        {
            get => (string)base.GetValue(CanvasShape.TextProperty);
            set => base.SetValue(CanvasShape.TextProperty, value);
        }
        #endregion

        #region 画笔颜色 —— Brush Stroke

        /// <summary>
        /// 画笔颜色依赖属性
        /// </summary>
        public static DependencyProperty StrokeProperty;

        /// <summary>
        /// 画笔颜色
        /// </summary>
        public Brush Stroke
        {
            get => (Brush)base.GetValue(CanvasShape.StrokeProperty);
            set => base.SetValue(CanvasShape.StrokeProperty, value);
        }

        #endregion

        #region 画笔粗细 —— Brush StrokeThickness

        /// <summary>
        /// 画笔粗细依赖属性
        /// </summary>
        public static DependencyProperty StrokeThicknessProperty;

        /// <summary>
        /// 画笔粗细
        /// </summary>
        public double StrokeThickness
        {
            get => (double)base.GetValue(CanvasShape.StrokeThicknessProperty);
            set => base.SetValue(CanvasShape.StrokeThicknessProperty, value);
        }

        #endregion

        #region 填充颜色 —— Brush Fill

        /// <summary>
        /// 填充颜色依赖属性
        /// </summary>
        public static DependencyProperty FillProperty;

        /// <summary>
        /// 填充颜色
        /// </summary>s
        public Brush Fill
        {
            get => (Brush)base.GetValue(CanvasShape.FillProperty);
            set => base.SetValue(CanvasShape.FillProperty, value);
        }

        #endregion

        #region 填充颜色 —— int ZIndex

        /// <summary>
        /// 填充颜色依赖属性
        /// </summary>
        public static DependencyProperty ZIndexProperty;

        /// <summary>
        /// 填充颜色
        /// </summary>s
        public int ZIndex
        {
            get => (int)base.GetValue(CanvasShape.ZIndexProperty);
            set => base.SetValue(CanvasShape.ZIndexProperty, value);
        }

        #endregion

        #endregion

        #region # 回调方法


        #endregion

        #region # 路由事件

        #region 点击形状路由事件 —— RoutedEvent _ShapeClickEvent

        /// <summary>
        /// 点击形状事件处理着
        /// </summary>
        public delegate void CanvasShapeClickEventHandler(object sender, CanvasShapeElementClickEventArgs e);

        /// <summary>
        /// 点击形状路由事件
        /// </summary>
        protected static readonly RoutedEvent _ShapeClickEvent;


        /// <summary>
        /// 点击形状路由事件处理程序
        /// </summary>
        public event CanvasShapeClickEventHandler ShapeClick
        {
            add { base.AddHandler(CanvasShape._ShapeClickEvent, value); }
            remove { base.RemoveHandler(CanvasShape._ShapeClickEvent, value); }
        }

        #endregion

        #region 型状绘制完成路由事件 —— RoutedEvent ShapeDrawn

        /// <summary>
        /// 型状绘制完成事件处理着
        /// </summary>
        public delegate void CanvasShapeDrawnEventHandler(object sender, CanvasShapeElementDrawnEventArgs e);

        /// <summary>
        /// 型状绘制完成路由事件
        /// </summary>
        protected static readonly RoutedEvent _ShapeDrawnEvent;

        /// <summary>
        /// 型状绘制完成路由事件处理程序
        /// </summary>
        public event CanvasShapeDrawnEventHandler ShapeDrawn
        {
            add => base.AddHandler(CanvasShape._ShapeDrawnEvent, value);
            remove => base.RemoveHandler(CanvasShape._ShapeDrawnEvent, value);
        }

        #endregion

        #region 型状绘制取消路由事件 —— RoutedEvent ShapeDrawCancel

        /// <summary>
        /// 型状绘制取消事件处理着
        /// </summary>
        public delegate void CanvasShapeDrawCancelEventHandler(object sender, CanvasShapeElementDrawCancelEventArgs e);

        /// <summary>
        /// 型状绘制取消路由事件
        /// </summary>
        protected static readonly RoutedEvent _ShapeDrawCancelEvent;

        /// <summary>
        /// 型状绘制取消路由事件处理程序
        /// </summary>
        public event CanvasShapeDrawCancelEventHandler ShapeDrawCancel
        {
            add => base.AddHandler(CanvasShape._ShapeDrawCancelEvent, value);
            remove => base.RemoveHandler(CanvasShape._ShapeDrawCancelEvent, value);
        }

        #endregion

        #endregion

        #region # 事件处理程序

        #endregion

        #region # 抽象方法

        // Public Abstract

        #region 绘制 —— abstract void Draw(PointX startPoint)
        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="startPoint">起点</param>
        public abstract void Draw(PointX startPoint);
        #endregion

        #region 绘制 —— abstract void Draw(double scale, ShapeX shapeX)
        /// <summary>
        /// 绘制
        /// </summary>
        public abstract void Draw(double scale, ShapeX shapeX);
        #endregion

        #region 拖拽 —— abstract void Drag(DraggedEventArgs draggedEventArgs)
        /// <summary>
        /// 拖拽
        /// </summary> 
        /// <param name="draggedEventArgs">拖拽参数</param>
        public abstract void Drag(DraggedEventArgs draggedEventArgs);
        #endregion


        // Protected Abstract

        #region 初始化形状控件 —— abstract Shape InitShapeElement()
        /// <summary>
        /// 初始化形状控件
        /// </summary>
        protected abstract Shape InitShapeElement();
        #endregion

        #endregion

        #region # 方法

        // Public Virtual

        #region 绘制取消 —— abstract void DrawCancel()
        /// <summary>
        /// 绘制取消
        /// </summary> 
        public virtual void DrawCancel()
        {
            this._parentCanvas?.Children.Remove(this.ShapeElement);
            this._parentCanvas?.Children.Remove(this);
        }
        #endregion

        // Private
        // 
        #region 初始化控件 —— void InitElement()
        /// <summary>
        /// 初始化控件
        /// </summary>
        private void InitElement()
        {
            this.ShapeElement = this.InitShapeElement();

            // 绑定菜单
            Binding menuBinding = new Binding(nameof(this.ContextMenu))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            this.ShapeElement.SetBinding(Shape.ContextMenuProperty, menuBinding);
            this.ShapeElement.SetValue(Shape.ContextMenuProperty, this.ContextMenu);

            // 绑定画笔
            Binding strokeBinding = new Binding(nameof(this.Stroke))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            this.ShapeElement.SetBinding(Shape.StrokeProperty, strokeBinding);
            this.ShapeElement.SetValue(Shape.StrokeProperty, this.Stroke);

            // 绑定画笔粗细
            Binding strokeThicknessBinding = new Binding(nameof(this.StrokeThickness))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            this.ShapeElement.SetBinding(Shape.StrokeThicknessProperty, strokeThicknessBinding);
            this.ShapeElement.SetValue(Shape.StrokeThicknessProperty, this.StrokeThickness);

            // 绑定填充颜色
            Binding fillBinding = new Binding(nameof(this.Fill))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            this.ShapeElement.SetBinding(Shape.FillProperty, fillBinding);
            this.ShapeElement.SetValue(Shape.FillProperty, this.Fill);

            // 绑定填充颜色
            Binding cursorBinding = new Binding(nameof(this.Cursor))
            {
                Source = this,
                Mode = BindingMode.TwoWay
            };
            this.ShapeElement.SetBinding(Shape.CursorProperty, cursorBinding);
            this.ShapeElement.SetValue(Shape.CursorProperty, this.Cursor);

        }
        #endregion

        #endregion
    }
}